﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MLSharp.Utilities
{
	/// <summary>
	/// Contains extension methods for <see cref="IList{T}"/>
	/// related classes.
	/// </summary>
	public static class ListExtensions
	{
		/// <summary>
		/// Adds the items from the specified collection
		/// to the specified list.
		/// </summary>
		/// <typeparam name="T">The type.</typeparam>
		/// <param name="list">The list to add items to.</param>
		/// <param name="collection">The items to add.</param>
		public static void AddRange<T>(this IList<T> list, IEnumerable<T> collection)
		{
			foreach (T obj in collection)
			{
				list.Add(obj);
			}
		}

		/// <summary>
		/// Searches for an element that matches the conditions defined by the specified predicate, 
		/// and returns the zero-based index of the first occurrence within the entire <see cref="IList{T}"/>.
		/// </summary>
		/// <typeparam name="T">The type.</typeparam>
		/// <param name="list">The list to search.</param>
		/// <param name="match">The predicate to evaluate for each possible match.</param>
		/// <returns>The zero-based index of the first occurance of an element that mathces the conditions 
		/// specified by match, if found; otherwise, -1.</returns>
		public static int FindIndex<T>(this IList<T> list, Predicate<T> match)
		{
			for (int i=0; i < list.Count; i++)
			{
				if (match(list[i]))
					return i;
			}

			return -1;
		}

		/// <summary>
		/// Calculates the standard deviation.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list"></param>
		/// <param name="selector"></param>
		/// <returns></returns>
		public static double StdDev<T>(this IList<T> list, Func<T,double> selector)
		{
			if (list.Count < 2)
			{
				return 0;
			}

			double average = list.Average(selector);

			double totalDeviation = list.Sum(i => Math.Pow(selector(i) - average, 2));

			double stddev = Math.Sqrt(totalDeviation / (list.Count - 1));

			return stddev;
		}
	}
}
